﻿#region GNU GPL Version 3 License

/// Copyright 2013 Shailesh Lolam
/// 
/// This file HttpApi.cs is part of AzEzAuto.
/// 
/// AzEzAuto is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
/// 
/// AzEzAuto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
/// 
/// You should have received a copy of the GNU General Public License along with AzEzAuto. If not, see http://www.gnu.org/licenses/.
/// 
/// History:
/// ______________________________________________________________
/// Created         04-2013             Shailesh Lolam

#endregion
      
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Xml.Serialization;
using System.Net;
using System.Collections.Specialized;
using System.IO;
using System.Diagnostics;

namespace AzEzAuto.Utils
{
    public class HttpApi
    {
        X509Certificate2 _certificate;
        IWebProxy _proxy;

        public HttpApi(X509Certificate2 certificate)
        {
            Guard.ArgumentNull(certificate, "certificate");
            _certificate = certificate;
        }

        public X509Certificate2 Certificate
        {
            set
            {
                _certificate = value;
            }
            get
            {
                return _certificate;
            }
        }

        public IWebProxy WebProxy
        {
            get
            {
                return _proxy;
            }
            set
            {
                _proxy = value;
            }
        }

        public T Get<T>(Uri uri, NameValueCollection headers)
        {
            T retVal = default(T);

            HttpWebRequest request = GetRequest(uri, "GET", headers);

            try
            {
                using (WebResponse response = request.GetResponse())
                {
                    headers.Clear();
                    headers.Add(response.Headers);

                    using (Stream stream = response.GetResponseStream())
                    using (TraceStream ls = new TraceStream(stream))
                    {
                        XmlSerializer s = new XmlSerializer(typeof(T));
                        retVal = (T)s.Deserialize(ls);
                    }
                }
            }
            catch //(WebException webEx)
            {
                throw;
            }

            return retVal;
        }

        public T Post<T>(Uri uri, string method, object value, NameValueCollection headers)
        {
            T retVal = default(T);

            HttpWebRequest request = GetRequest(uri, method, headers);
            if (value != null)
            {
                request.ContentType = "application/xml";
                using (Stream stream = request.GetRequestStream())
                using (TraceStream ls = new TraceStream(stream))
                {
                    XmlSerializer s = new XmlSerializer(value.GetType());
                    s.Serialize(ls, value);
                }
            }

            using (WebResponse response = request.GetResponse())
            {
                headers.Clear();
                headers.Add(response.Headers);

                using (Stream stream = response.GetResponseStream())
                using (TraceStream ls = new TraceStream(stream))
                {
                    XmlSerializer s = new XmlSerializer(typeof(T));
                    retVal = (T)s.Deserialize(ls);
                }
            }

            return retVal;
        }

        public void Get(Uri uri, NameValueCollection headers)
        {
            HttpWebRequest request = GetRequest(uri, "GET", headers);

            using (WebResponse response = request.GetResponse())
            {
                headers.Clear();
                headers.Add(response.Headers);
            }
        }

        public void Post(Uri uri, string method, object value, NameValueCollection headers)
        {
            HttpWebRequest request = GetRequest(uri, method, headers);
            if (value != null)
            {
                request.ContentType = "application/xml";
                using (Stream stream = request.GetRequestStream())
                using (TraceStream ls = new TraceStream(stream))
                {
                    XmlSerializer s = new XmlSerializer(value.GetType());
                    s.Serialize(ls, value);
                }
            }

            using (WebResponse response = request.GetResponse())
            {
                headers.Clear();
                headers.Add(response.Headers);
            }
        }


        private HttpWebRequest GetRequest(Uri uri, string method, NameValueCollection headers)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            if (_certificate != null)
                request.ClientCertificates.Add(_certificate);
            if (_proxy != null)
                request.Proxy = _proxy;
            request.ProtocolVersion = HttpVersion.Version11;
            request.Headers.Add(headers);
            request.Method = method;

            return request;
        }
    }

    public class TraceStream : Stream
    {
        Stream _stream;

        public TraceStream(Stream stream)
        {
            Guard.ArgumentNull(stream, "stream");
            _stream = stream;
        }

        public override bool CanRead
        {
            get { return _stream.CanRead; }
        }

        public override bool CanSeek
        {
            get { return _stream.CanSeek; }
        }

        public override bool CanWrite
        {
            get { return _stream.CanWrite; }
        }

        public override void Flush()
        {
            _stream.Flush();
        }

        public override long Length
        {
            get { return _stream.Length; }
        }

        public override long Position
        {
            get
            {
                return _stream.Position;
            }
            set
            {
                _stream.Position = value;
            }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            int r = _stream.Read(buffer, offset, count);
            Trace.TraceInformation(UTF8Encoding.UTF8.GetString(buffer, offset, r));
            return r;
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _stream.Seek(offset, origin);
        }

        public override void SetLength(long value)
        {
            _stream.SetLength(value);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            Trace.TraceInformation(UTF8Encoding.UTF8.GetString(buffer, offset, count));
            _stream.Write(buffer, offset, count);
        }
    }
}
